﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using WeifenLuo.WinFormsUI.Docking;
using DBSourceToolsLib.Composite;

namespace DBSourceTools
{
    public class WindowList : DBSourceToolsLib.Interfaces.ISourceEditorObserver, Interfaces.IWindowListSubject
    {
        private static WindowList m_Singleton;
        private static bool m_bIsCreated = false;
        private static SortedList<string, MainPanelForm> m_SourceList = new SortedList<string, MainPanelForm>();
        private static DockPanel m_DockPanelMain;
        

        private WindowList()
        {
            m_Singleton = this;
            m_bIsCreated = true;
        }

        public static WindowList Instance() {
            if (!m_bIsCreated)
                m_Singleton = new WindowList();
            m_bIsCreated = true;
            return m_Singleton;
        }

        public void SetDockPanelMain(DockPanel oDocPanelMain)
        {
            m_DockPanelMain = oDocPanelMain;
        }

        public void AddWindow(string strKey, MainPanelForm oForm)
        {
            m_SourceList.Add(strKey, oForm);
            oForm.RegisterInterestInSourceEditor(this);
            oForm.Show(m_DockPanelMain);
            
        }

        public void RemoveWindow(string strDatabase, string strType, string strObject)
        {
            string windowKey = strDatabase + "." + strType + "." + strObject;
            if (m_SourceList.ContainsKey(windowKey))
            {
                m_SourceList[windowKey].Close();
                m_SourceList.Remove(windowKey);
            }
            if (!strDatabase.Equals("SrvExplorer"))
            {
                NotifyObservers(new TreeNodeTag(strDatabase, strType, strObject, null), Interfaces.WindowListObserverEvent.WindowClosed);
            }
        }


        private void FocusWindow(TreeNodeTag treeNodeTag)
        {
            FocusWindow(treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName, null);
        }

        public void FocusWindow(string strDatabase, string strType, string strObject, string strParams)
        {
            string windowKey = strDatabase + "." + strType + "." + strObject;

            if (m_SourceList.ContainsKey(windowKey))
            {
                m_SourceList[windowKey].Focus();
                // check for a change of line number
                if (!String.IsNullOrEmpty(strParams))
                {
                    switch (strType)
                    {
                        case "File":
                            int iLine;
                            if (Int32.TryParse(strParams, out iLine))
                            {
                                TextEditorForm oTextForm = (TextEditorForm)m_SourceList[windowKey];
                                oTextForm.GotoLine(iLine);
                            }
                            break;
                    }
                }

            }

            if (!windowKey.Equals("All.Search.Search") && !windowKey.Equals("SrvExplorer.."))
            {
                NotifyObservers(new TreeNodeTag(strDatabase, strType, strObject, null)
                    , Interfaces.WindowListObserverEvent.WindowFocused);
            }

        }

        private bool HasWindow(TreeNodeTag treeNodeTag)
        {
            return HasWindow(treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName);
        }

        internal bool HasWindow(string strDatabase, string strType, string strObject)
        {
            string windowKey = strDatabase + "." + strType + "." + strObject;
            return m_SourceList.ContainsKey(windowKey);
        }

        internal void CloseAll()
        {
            List<string> lCurrentKeys = new List<string>();
            foreach (string strWindowKey in m_SourceList.Keys)
            {
                if (strWindowKey.Equals("All.Search.Search") 
                    || strWindowKey.Equals("DBExplorer")
                    || strWindowKey.Equals("SrvExplorer")
                    )
                {
                    // ignore search and dbexplorer.

                }
                else
                {
                    lCurrentKeys.Add(strWindowKey);
                }
            }
            foreach (string strKey in lCurrentKeys)
                ((MainPanelForm)m_SourceList[strKey]).Close();

        }

        public void NotifyEvent(string strDatabase, string strType, string strObject, DBSourceToolsLib.Interfaces.SourceEditorEvent oEvent, string strParams)
        {
            string strWindowKey = strDatabase + "." + strType + "." + strObject;
            switch (oEvent)
            {
                case DBSourceToolsLib.Interfaces.SourceEditorEvent.Close:
                    {
                        if (m_SourceList.ContainsKey(strWindowKey))
                            m_SourceList.Remove(strWindowKey);
                    }
                    break;
                #region old code not used
                //case DBSourceToolsLib.Interfaces.SourceEditorEvent.IsCurrent:
                //    {
                //        //if (this.m_SourceList.ContainsKey(message))
                //        //    this.m_CurrentSourceEditor = (MainPanelForm)this.m_SourceList[message];
                //    }
                //    break;
                //case DBSourceToolsLib.Interfaces.SourceEditorEvent.Deleted:
                //    {
                //        //if (strObject.CompareTo("Database") == 0)
                //        //    oDBExplorer.UpdateTreeViewDatabases();
                //        //else
                //        //    oDBExplorer.UpdateTreeView(strDatabase);
                //    }
                //    break;
                //case DBSourceToolsLib.Interfaces.SourceEditorEvent.Rename:
                //    {
                //        //this.DBExplorer_ObjectRename(strDatabase, strType, strObject, strParams);
                //        //oDBExplorer.UpdateTreeView(strDatabase);
                //    }
                //    break;
                //case DBSourceToolsLib.Interfaces.SourceEditorEvent.DBRename:
                //    {
                //        //this.DBExplorer_ObjectRename(strDatabase, strType, strObject, strParams);
                //        //oDBExplorer.UpdateTreeViewDatabases();
                //    }
                //    break;
                //case DBSourceToolsLib.Interfaces.SourceEditorEvent.FileOpened:
                //    {
                //        //this.DBExplorer_SelectChanged(strDatabase, strType, strObject, null);
                //        //UserSettings.Instance().AddRecentFile(strObject);

                //    }
                //    break;
                //case DBSourceToolsLib.Interfaces.SourceEditorEvent.TargetDeleted:
                //    {
                //        //                        this.oDBExplorer.UpdateTreeViewDatabases();
                //    }
                //    break;
                #endregion

            }

        }

        internal void ShowWindow(TreeNodeTag treeNodeTag, string strParams = null)
        {
            if (HasWindow(treeNodeTag))
            {
                FocusWindow(treeNodeTag);
                m_SourceList[GetWindowKey(treeNodeTag)].Show();
            }
            else
            {
                string strWindowKey = GetWindowKey(treeNodeTag);
                switch (treeNodeTag.ObjectType)
                {
                    case "Dependency Tree":
                        DependencyTreeForm oDepTreeForm = new DependencyTreeForm
                            (treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName);
                        //oDepTreeForm.RegisterInterestInSourceEditor(this);
                        WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), oDepTreeForm);
                        //this.m_SourceList.Add(windowKey, oDepTreeForm);
                        oDepTreeForm.Show(m_DockPanelMain);
                        NotifyObservers(treeNodeTag, Interfaces.WindowListObserverEvent.WindowOpened);
                        break;
                    case "Deployment Target":
                        {
                            DatabaseForm odtForm = new DatabaseForm
                                (treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName);
                            WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), odtForm);
                            odtForm.Show(m_DockPanelMain);
                            NotifyObservers(treeNodeTag, Interfaces.WindowListObserverEvent.WindowOpened);
                        }
                        break;
                    case "Database":
                        {
                            DatabaseForm odtForm = new DatabaseForm
                                (treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName);
                            //odtForm.RegisterInterestInSourceEditor(this);
                            WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), odtForm);
                            //this.m_SourceList.Add(windowKey, odtForm);
                            odtForm.Show(m_DockPanelMain);
                            NotifyObservers(treeNodeTag, Interfaces.WindowListObserverEvent.WindowOpened);
                        }
                        break;
                    case "Data":
                        {
                            DataForm oDataForm = new DataForm
                                (treeNodeTag.DatabaseName, "Data", treeNodeTag.ObjectName);
                            //(strDatabase, "Data", strObject);
                            //oDataForm.RegisterInterestInSourceEditor(this);
                            WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), oDataForm);
                            //this.m_SourceList.Add(windowKey, oDataForm);
                            oDataForm.Show(m_DockPanelMain);
                            NotifyObservers(treeNodeTag, Interfaces.WindowListObserverEvent.WindowOpened);
                        }
                        break;
                    case "File":
                        {
                            if (System.IO.File.Exists(treeNodeTag.ObjectName))
                            {
                                TextEditorForm oTextForm = new TextEditorForm
                                    (treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName,
                                    DBSourceToolsLib.SysObjects.QueryType.NewQuery, strParams);
                                //oTextForm.RegisterInterestInSourceEditor(this);
                                WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), oTextForm);

                                //this.m_SourceList.Add(windowKey, oTextForm);
                                oTextForm.Show(m_DockPanelMain);
                                NotifyObservers(treeNodeTag, Interfaces.WindowListObserverEvent.WindowOpened);
                            }
                            //else
                            //{
                            //    UserSettings.Instance().RemoveRecentFile(strObject);
                            //    this.oDBExplorer.UpdateTreeViewDatabases();
                            //    UserSettings.Instance().SaveRecentFileList();
                            //}
                        }
                        break;
                    case "Queries":
                        {
                            //SourceDatabase oSource = UserSettings.Instance().getSourceDatabase(strDatabase);

                            //string strNewQueryName = oSource.BaseDirectory + "\\Queries\\" +
                            //    strObject + ".sql";

                            //TextEditorForm oTextForm = new TextEditorForm(strDatabase, strType, strNewQueryName
                            //    , DBSourceToolsLib.SysObjects.QueryType.NewQuery, strParams);
                            ////oTextForm.RegisterInterestInSourceEditor(this);
                            //WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), oTextForm);
                            ////this.m_SourceList.Add(windowKey, oTextForm);
                            //oTextForm.Show(m_DockPanelMain);
                        }

                        break;
                    case "CompareResults":
                        {

                            CompareResultsForm oResultsform = new CompareResultsForm(
                                treeNodeTag.DatabaseName, treeNodeTag.ObjectType, treeNodeTag.ObjectName);
                            oResultsform.TargetDatabaseNick = strParams;
                            //oResultsform.RegisterInterestInSourceEditor(this);
                            WindowList.Instance().AddWindow(GetWindowKey(treeNodeTag), oResultsform);
                            //this.m_SourceList.Add(windowKey, oResultsform);
                            oResultsform.Show(m_DockPanelMain);
                        }
                        break;
                    default:
                        //MessageBox.Show("default case not handled");

                        break;
                }
                //this.Cursor = Cursors.Default;
            }

        }

        private string GetWindowKey(TreeNodeTag treeNodeTag)
        {
            return treeNodeTag.DatabaseName + "." + treeNodeTag.ObjectType + "." + treeNodeTag.ObjectName;
        }

        #region window list observer methods

        List<Interfaces.IWindowListObserver> m_Observers = new List<Interfaces.IWindowListObserver>();

        public void RegisterInterestInWindowList(Interfaces.IWindowListObserver observer)
        {
            m_Observers.Add(observer);
        }

        public void NotifyObservers(TreeNodeTag oTreeNodeTag, Interfaces.WindowListObserverEvent oEvent)
        {
            foreach (Interfaces.IWindowListObserver oObserver in m_Observers)
                oObserver.NotifyEvent(oTreeNodeTag, oEvent);
        }

        #endregion
    }
}
